/*
Borealis Library
A library of commonly used hydrological modeling building blocks

Copyright (C) 2008  Chris Marsh

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "include/borealis/Logger.hpp"

namespace Borealis
{
	Logger Logger::m_instance;

	void Logger::InitLog(const std::string &sFile)
	{
		//Make sure log file is not already open
		if (m_loaded)
			//throw std::runtime_error("A log file is already open.\nStack Logger::InitLog()");
			return;

		//Open file
		m_file = CreateFile (sFile.c_str (), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
		if (m_file == INVALID_HANDLE_VALUE)
			throw std::runtime_error("CreateFile returned invalid handle value.\nStack Logger::InitLog()");

		//Set file loaded flag
		m_loaded = TRUE;

		//Set filename
		m_filename = sFile;

		//Write RTF header
		WriteString ("{\\rtf1\\ansi\\deff0{\\fonttbl{\\f0 Courier New;}}\\fs20\n");

		//Write colour table
		WriteString ("{\\colortbl;\n");                     //Black
		WriteString ("\\red255\\green255\\blue255;\n");     //White
		WriteString ("\\red128\\green128\\blue128;\n");     //Grey
		WriteString ("\\red255\\green0\\blue0;\n");         //Red
		WriteString ("\\red0\\green255\\blue0;\n");         //Green
		WriteString ("\\red0\\green0\\blue255;\n");         //Blue
		WriteString ("\\red0\\green255\\blue255;\n");       //Cyan
		WriteString ("\\red255\\green255\\blue0;\n");       //Yellow
		WriteString ("\\red255\\green0\\blue255;\n");       //Magenta
		WriteString ("\\red128\\green0\\blue0;\n");         //Dark Red
		WriteString ("\\red0\\green128\\blue0;\n");         //Dark Green
		WriteString ("\\red0\\green0\\blue128;\n");         //Dark Blue
		WriteString ("\\red255\\green128\\blue128;\n");     //Light Red
		WriteString ("\\red128\\green255\\blue128;\n");     //Light Green
		WriteString ("\\red128\\green128\\blue255;\n");     //Light Blue
		WriteString ("\\red255\\green128\\blue0;\n");       //Orange
		WriteString ("}\n");

		//Write log header
		LogString ("*** Logging Started");
		LogString ("");

	}

	void Logger::Close()
	{
		//Make sure log file is already opened
		if (!m_loaded)
			Borealis::Logger::GetInstance().InitLog("Borealis_Debug_log.log");

		//Write closing line
		LogString ("");
		LogString ("*** Logging Ended");

		//Write closing brace
		WriteString ("}");

		//Close file
		CloseHandle (m_file);

		//Clear file loaded flag
		m_loaded = FALSE;
	}

	bool Logger::IsOpen()
	{
		return m_loaded;
	}

	void Logger::LogString( std::string sText )
	{
		//Make sure log file is already opened
		if (!m_loaded)
			Borealis::Logger::GetInstance().InitLog("Borealis_Debug_log.log");

		//Format string
		DoFormatting (&sText);

		//Write string to file
		WriteString (sText);
	}

	void Logger::LogMessage( const std::string &sSource, const std::string& sMessage, MESSAGETYPE messageType )
	{
		std::string sString;

		//Make sure log file is already opened
		if (!m_loaded)
			Borealis::Logger::GetInstance().InitLog("Borealis_Debug_log.log");

		switch (messageType)
		{
		case MSG_SUCCESS:
			sString = "[BLUE]";
			break;

		case MSG_INFO:
			sString = "[GREY]";
			break;

		case MSG_WARN:
			sString = "[ORANGE]";
			break;

		case MSG_ERROR:
			sString = "[RED]";
			break;
		}

		sString += "[B]<";
		sString += sSource;
		sString += ">[/B] ";
		sString += sMessage;

		//Format the string and write it to the log file
		LogString (sString);

		
	}

	void Logger::DoFormatting( std::string* sText )
	{
		//Fix special symbols {, }, and backslash
		ReplaceTag (sText, "\\", "\\\\");
		ReplaceTag (sText, "{", "\\{");
		ReplaceTag (sText, "}", "\\}");

		//Colours
		ReplaceTag (sText, "[BLACK]", "\\cf0 ");
		ReplaceTag (sText, "[WHITE]", "\\cf1 ");
		ReplaceTag (sText, "[GREY]", "\\cf2 ");
		ReplaceTag (sText, "[RED]", "\\cf3 ");
		ReplaceTag (sText, "[GREEN]", "\\cf4 ");
		ReplaceTag (sText, "[BLUE]", "\\cf5 ");
		ReplaceTag (sText, "[CYAN]", "\\cf6 ");
		ReplaceTag (sText, "[YELLOW]", "\\cf7 ");
		ReplaceTag (sText, "[MAGENTA]", "\\cf8 ");
		ReplaceTag (sText, "[DARK_RED]", "\\cf9 ");
		ReplaceTag (sText, "[DARK_GREEN]", "\\cf10 ");
		ReplaceTag (sText, "[DARK_BLUE]", "\\cf11 ");
		ReplaceTag (sText, "[LIGHT_RED]", "\\cf12 ");
		ReplaceTag (sText, "[LIGHT_GREEN]", "\\cf13 ");
		ReplaceTag (sText, "[LIGHT_BLUE]", "\\cf14 ");
		ReplaceTag (sText, "[ORANGE]", "\\cf15 ");

		//Text style
		ReplaceTag (sText, "[PLAIN]", "\\plain ");
		ReplaceTag (sText, "[B]", "\\b ");
		ReplaceTag (sText, "[/B]", "\\b0 ");
		ReplaceTag (sText, "[I]", "\\i ");
		ReplaceTag (sText, "[/I]", "\\i0 ");
		ReplaceTag (sText, "[U]", "\\ul ");
		ReplaceTag (sText, "[/U]", "\\ul0 ");
		ReplaceTag (sText, "[S]", "\\strike ");
		ReplaceTag (sText, "[/S]", "\\strike0 ");
		ReplaceTag (sText, "[SUB]", "\\sub ");
		ReplaceTag (sText, "[/SUB]", "\\sub0 ");
		ReplaceTag (sText, "[SUPER]", "\\super ");
		ReplaceTag (sText, "[/SUPER]", "\\super0 ");
		ReplaceTag (sText, "[LEFT]", "\\ql ");
		ReplaceTag (sText, "[RIGHT]", "\\qr ");
		ReplaceTag (sText, "[CENTER]", "\\qc ");
		ReplaceTag (sText, "[FULL]", "\\qj ");
		ReplaceTag (sText, "[TITLE]", "\\fs40 ");
		ReplaceTag (sText, "[/TITLE]", "\\fs20 ");
		ReplaceTag (sText, "[H]", "\\fs24 ");
		ReplaceTag (sText, "[/H]", "\\fs20 ");
	//	ReplaceTag (sText, "\n","\\line");

		//Add brackets and line formatting tags
		sText->insert (0, "{\\pard ");
		sText->insert (sText->length (), "\\par}\n");
	}

	void Logger::ReplaceTag( std::string* sText, const std::string& sTag, const std::string& sReplacement )
	{
		int start = 0;

		while (sText->find(sTag, start) != std::string::npos)
		{
			start = (int) sText->find(sTag, start);
			sText->replace (start, sTag.length (), sReplacement);
			start += (int) sTag.length () + 1;
		}
	}

	void Logger::WriteString( const std::string& sText )
	{
		DWORD bytesWritten;

		WriteFile (m_file, sText.c_str (), (int) sText.length (), &bytesWritten, NULL);
	}

	Logger::Logger()
	{
		this->m_loaded = false;
		this->m_file = "";
	}

	Logger::~Logger()
	{
		if(m_loaded)
			Close();
	}

	Logger& Logger::GetInstance()
	{
		return m_instance;
	}

}